﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace UControls
{
   
    public partial class ucCalculator : UserControl
    {
        public ucCalculator()
        {
            InitializeComponent();
            calcData = new CCalculatorData();
            this.DataContext = calcData;

            calcData.currentScreen = 0;
            calcData.firstOperand = 0;
            calcData.memoryVariable = 0;
            calcData.currentOperation = CCalculatorData.EOpertaion.eNoOperation;
            decimalOperation = false;
        }

        private CCalculatorData calcData;
        
        public bool decimalOperation { get; set; }
        private int decimalDigit;

        private void Operation_Button_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;

            if (sender == null) return;

            switch (btn.Content.ToString())
            {
                case "0":
                    addDigit(0);
                    break;
                case "1":
                    addDigit(1);
                    break;
                case "2":
                    addDigit(2);
                    break;
                case "3":
                    addDigit(3);
                    break;
                case "4":
                    addDigit(4);
                    break;
                case "5":
                    addDigit(5);
                    break;
                case "6":
                    addDigit(6);
                    break;
                case "7":
                    addDigit(7);
                    break;
                case "8":
                    addDigit(8);
                    break;
                case "9":
                    addDigit(9);
                    break;
                case "+":
                    SetCurrentOperatorAndClear(CCalculatorData.EOpertaion.ePlus);
                    break;
                case "-":
                    SetCurrentOperatorAndClear(CCalculatorData.EOpertaion.eMinus);
                    break;
                case "X":
                    SetCurrentOperatorAndClear(CCalculatorData.EOpertaion.eMultiply);
                    break;                
                case "/":
                    SetCurrentOperatorAndClear(CCalculatorData.EOpertaion.eDivide);
                    break;
                case ".":
                    if (decimalOperation != true)
                    {
                        decimalOperation = true;
                        decimalDigit = 1;
                    }
                    break;

                case "x^y":
                    SetCurrentOperatorAndClear(CCalculatorData.EOpertaion.eXpowY);

                    break;
                
                default:
                    break;
            }

            
        }

        /// <summary>
        /// Switch value of CurrentScreen to FirstOperand
        /// </summary>
        /// <param name="eOpertaion"></param>
        private void SetCurrentOperatorAndClear(CCalculatorData.EOpertaion eOpertaion)
        {
            switch ( calcData.currentOperation)
            {
                case CCalculatorData.EOpertaion.ePlus:
                    calcData.firstOperand += calcData.currentScreen;
                    break;
                case CCalculatorData.EOpertaion.eMinus:
                    calcData.firstOperand -= calcData.currentScreen;
                    break;
                case CCalculatorData.EOpertaion.eDivide:
                    calcData.firstOperand = calcData.currentScreen != 0 ? calcData.firstOperand / calcData.currentScreen : 0; 
                    break;
                case CCalculatorData.EOpertaion.eMultiply:
                    calcData.firstOperand *= calcData.currentScreen;
                    break;
                case CCalculatorData.EOpertaion.eNoOperation:
                    calcData.firstOperand = calcData.currentScreen;                    
                    break;
                case CCalculatorData.EOpertaion.eXpowY:
                    calcData.firstOperand = Math.Pow(calcData.firstOperand, calcData.currentScreen);
                    break;
                default:
                    break;
            }
            calcData.currentScreen = 0;
            calcData.currentOperation = eOpertaion;
            decimalOperation = false;
        }

        private void addDigit(int pNumber)
        {
            if(decimalOperation == false )
            {

                calcData.currentScreen = calcData.currentScreen * 10 + pNumber;
            }
            else
            {
                calcData.currentScreen += (double)pNumber / Math.Pow(10, decimalDigit);                    
                decimalDigit++;
            }

            
        }

      /// <summary>
      /// action to be performed on equal button
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
        private void Operation_EQUAL_Button_Click(object sender, RoutedEventArgs e)
        {
            switch (calcData.currentOperation)
            {
                case CCalculatorData.EOpertaion.ePlus:
                    calcData.currentScreen += calcData.firstOperand;
                    break;
                case CCalculatorData.EOpertaion.eMinus:
                    calcData.currentScreen = calcData.firstOperand - calcData.currentScreen;
                    break;
                case CCalculatorData.EOpertaion.eDivide:
                    calcData.currentScreen = calcData.currentScreen != 0 ? calcData.firstOperand / calcData.currentScreen : 0;                                        
                    break;
                case CCalculatorData.EOpertaion.eMultiply:
                    calcData.currentScreen *= calcData.firstOperand;
                    break;
                case CCalculatorData.EOpertaion.eXpowY:
                    calcData.currentScreen = Math.Pow(calcData.firstOperand,calcData.currentScreen);
                    break;
                case CCalculatorData.EOpertaion.eNoOperation:
                    break;


                default:
                    break;
            }


            ResetScreenData(calcData.currentScreen);
            
        }

        private void ResetScreenData(double forCurrentScreen)
        {
            calcData.currentOperation = CCalculatorData.EOpertaion.eNoOperation;
            calcData.currentScreen = forCurrentScreen;
            calcData.firstOperand = 0;
            decimalOperation = false;
        }

        private void Operation_PLUSMINUS_Button_Click(object sender, RoutedEventArgs e)
        {
            calcData.currentScreen *= -1;
        }

        private void Operation_CLEAN_Button_Click(object sender, RoutedEventArgs e)
        {
            ResetScreenData(0);
            
        }

        private void Operation_MR_Button_Click(object sender, RoutedEventArgs e)
        {
            ResetScreenData(calcData.memoryVariable);
            

        }

        private void Operation_MC_Button_Click(object sender, RoutedEventArgs e)
        {
            calcData.memoryVariable = 0;
            calcData.currentScreen = 0;
        }

        private void Operation_MPLUS_Button_Click(object sender, RoutedEventArgs e)
        {
            calcData.memoryVariable += calcData.currentScreen;
            calcData.currentScreen = 0;

        }
        private void Operation_MMINUS_Button_Click(object sender, RoutedEventArgs e)
        {
            calcData.memoryVariable -= calcData.currentScreen;
            calcData.currentScreen = 0;
        }

        private void Operation_MSave_Button_Click(object sender, RoutedEventArgs e)
        {
            calcData.memoryVariable = calcData.currentScreen;
            calcData.currentScreen = 0;
        }


        /// <summary>
        /// perform SQRT operation on number!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Operation_SQRT_Button_Click(object sender, RoutedEventArgs e)
        {
            calcData.currentScreen =
            Math.Sqrt(calcData.currentScreen);
        }

        /// <summary>
        /// calculate 1 upon X
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Operation_ONEUPONX_Button_Click(object sender, RoutedEventArgs e)
        {
            if (calcData.currentScreen == 0) return;
            calcData.currentScreen = 1 / calcData.currentScreen;            
        }

        private void Operation_XPOW2_Button_Click(object sender, RoutedEventArgs e)
        {
            calcData.currentScreen =
           Math.Pow(calcData.currentScreen,2);
        }

        private void Operation_XPOW3_Button_Click(object sender, RoutedEventArgs e)
        {
            calcData.currentScreen =
           Math.Pow(calcData.currentScreen, 3);
        }        
        
    }

    public class CCalculatorData : INotifyPropertyChanged
    {

        public enum EOpertaion { ePlus, eMinus, eDivide, eMultiply, eNoOperation, eXpowY };
        public EOpertaion currentOperation { get; set; }
        private double _currentScreen;
        public Double currentScreen
        {
            get
            {
                return _currentScreen;
            }
            set
            {
                _currentScreen = value;
                OnPropertyChange("currentScreen");
            }
        }
        private double _firstOperand;
        public Double firstOperand
        {
            get
            {
                return _firstOperand;
            }
            set
            {
                _firstOperand = value;
                OnPropertyChange("firstOperand");
            }
        }

        private string _memDisplay;

        public string MemDisplay
        {
            get { return _memDisplay; }
            set
            {
                _memDisplay = value;
                OnPropertyChange("MemDisplay");
            }
        }

        private double _memoryVariable;
        public Double memoryVariable
        {
            get
            {
                return _memoryVariable;
            }
            set
            {
                _memoryVariable = value;
                MemDisplay = _memoryVariable != 0 ? "M" : "";

            }
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChange(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        #endregion
    }


}
